package com.example.demo.util;

import com.example.demo.entity.AbstractPospMessage;
import com.example.demo.entity.AbstractPospResponseMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.persistence.Column;
import java.lang.reflect.Field;
import java.net.URLDecoder;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

public class PospVerifyUtils {
    private static final Logger logger = LoggerFactory.getLogger(PospVerifyUtils.class);

    public static Map<String, String> getQueryparams(String queryStr) {
        Map<String, String> keyValueMap = new HashMap<>();
        if (StringUtils.isNotEmpty(queryStr)) {
            String[] params = queryStr.split("&");
            for (String keyValue : params) {
                String[] kv = keyValue.split("=");
                if (kv.length != 2) {
                    logger.info("kv 不是合法的key-value:{}", kv);
                    continue;
                }
                keyValueMap.put(kv[0], kv[1]);
            }
        }
        return keyValueMap;
    }

    public static Map<String, String> sortMap(Map<String, String> sourceMap) {
        Map<String, String> targetMap = new TreeMap<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                int r = o1.compareTo(o2);
                return r;
            }
        });
        targetMap.putAll(sourceMap);
        return targetMap;
    }

    public static String getQueryparamStr(Map<String, String> keyValueMap) {
        StringBuilder sbr = new StringBuilder();
        for (String key : keyValueMap.keySet()) {
            sbr.append(key).append("=").append(keyValueMap.get(key)).append("&");
        }
        if (sbr.length() > 0) {
            sbr.deleteCharAt(sbr.length() - 1);
        }
        return sbr.toString();
    }

    public static String getEncryptionDate(Object requestObject, String queryStr, Map<String, String> otherMap) {

        Map<String, String> keyValueMap = new HashMap<>();
        if (StringUtils.isNotEmpty(queryStr)) keyValueMap.putAll(getQueryparams(queryStr));
        keyValueMap.putAll(otherMap);

        if (requestObject != null) {
            Field[] fields = requestObject.getClass().getDeclaredFields();
            for (Field field : fields) {
                Column column = field.getAnnotation(Column.class);
                if (column == null) continue;
                String name = field.getName();
                String value = null;
                try {
                    Object o = BeanUtils.forceGetProperty(requestObject, name);
                    if (o != null) value = o.toString();
                } catch (NoSuchFieldException e) {
                    continue;
                }
                if (StringUtils.isNotEmpty(value)) keyValueMap.put(name, value);
            }
            if (requestObject.getClass().getSuperclass() == AbstractPospMessage.class
                    || requestObject.getClass().getSuperclass() == AbstractPospResponseMessage.class) {
                fields = requestObject.getClass().getSuperclass().getDeclaredFields();
                for (Field field : fields) {
                    Column column = field.getAnnotation(Column.class);
                    if (column == null) continue;
                    String name = field.getName();
                    String value = null;
                    boolean accessible = field.isAccessible();
                    field.setAccessible(true);
                    Object o = null;
                    try {
                        o = field.get(requestObject);
                    } catch (IllegalAccessException e) {
                    }
                    field.setAccessible(accessible);
                    if (o != null) value = o.toString();
                    if (StringUtils.isNotEmpty(value)) keyValueMap.put(name, value);
                }
            }
        }

        keyValueMap = sortMap(keyValueMap);
        String encryptionData = getQueryparamStr(keyValueMap);
        return encryptionData;
    }
}
